#ifndef __PROCESS_HPP
#define __PROCESS_HPP

#include ".\Object.hpp"
//#include ".\Handle.hpp"

struct sStartupInfo : public STARTUPINFO
{
	sStartupInfo()
	{
		memset( this, 0, sizeof( *this ) );
		cb = sizeof( STARTUPINFO );
	}
	sStartupInfo( LPTSTR desktop, LPTSTR title, DWORD x, DWORD y, DWORD x_size, DWORD y_size, DWORD x_count_chars, DWORD y_count_chars, DWORD fill_attribute, DWORD flags, WORD show_window, HANDLE std_input, HANDLE std_output, HANDLE std_error )
	{
		cb = sizeof( STARTUPINFO );  
		lpReserved = NULL;
		lpDesktop = desktop; 
		lpTitle = title;  
		dwX = x;  
		dwY = y;  
		dwXSize = x_size;  
		dwYSize = y_size;  
		dwXCountChars = x_count_chars;  
		dwYCountChars = y_count_chars;  
		dwFillAttribute = fill_attribute;  
		dwFlags = flags;  
		wShowWindow = show_window;  
		cbReserved2 = 0;  
		lpReserved2 = NULL;  
		hStdInput = std_input;  
		hStdOutput = std_output;  
		hStdError = std_error;
	}
};

/*
class cSubStartupInfo : public cSubObject
{
	sStartupInfo StartupInfo;
public:
	cSubStartupInfo()
		: StartupInfo()
	{
	}
	cSubStartupInfo( LPTSTR desktop, LPTSTR title, DWORD x, DWORD y, DWORD x_size, DWORD y_size, DWORD x_count_chars, DWORD y_count_chars, DWORD fill_attribute, DWORD flags, WORD show_window, HANDLE std_input, HANDLE std_output, HANDLE std_error )
		: StartupInfo( desktop, title, x, y, x_size, y_size, x_count_chars, y_count_chars, fill_attribute, flags, show_window, std_input, std_output, std_error )
	{
	}
	virtual ~cSubStartupInfo()
	{
	}
	LPSTARTUPINFO Pointer()
	{
		return &StartupInfo;
	}
};

class cStartupInfo 
{
	cSubStartupInfo *SubStartupInfo;
public:
	cStartupInfo()
		: SubStartupInfo( new cSubStartupInfo() )
	{
	}
	cStartupInfo( LPTSTR desktop, LPTSTR title, DWORD x, DWORD y, DWORD x_size, DWORD y_size, DWORD x_count_chars, DWORD y_count_chars, DWORD fill_attribute, DWORD flags, WORD show_window, HANDLE std_input, HANDLE std_output, HANDLE std_error )
		: SubStartupInfo( new cSubStartupInfo( desktop, title, x, y, x_size, y_size, x_count_chars, y_count_chars, fill_attribute, flags, show_window, std_input, std_output, std_error ) )
	{
	}
	cStartupInfo( const cStartupInfo &startup_info )
		: SubStartupInfo( startup_info.SubStartupInfo )
	{
		SubStartupInfo->Attach();
	}
	~cStartupInfo()
	{
		SubStartupInfo->Detach();
	}
	cStartupInfo &operator =( const cStartupInfo &startup_info )
	{
		SubStartupInfo->Detach();
		SubStartupInfo = startup_info.SubStartupInfo;
		SubStartupInfo->Attach();
		return *this;
	}
	LPSTARTUPINFO Pointer()
	{
		return SubStartupInfo->Pointer();
	}
};/**/

class cSubProcess : public cSubObject
{
	PROCESS_INFORMATION ProcessInfo;
public:
	cSubProcess( const PROCESS_INFORMATION &process_info )
		: ProcessInfo( process_info )
	{
	}
	virtual ~cSubProcess()
	{
		CloseHandle( ProcessInfo.hThread );
		CloseHandle( ProcessInfo.hProcess );
	}
	HANDLE ProcessHandle() const 
	{
		return ProcessInfo.hProcess;
	}
	HANDLE ThreadHandle() const 
	{
		return ProcessInfo.hThread;
	}
};

class cProcess : public cObject< cSubProcess >
{
public:
	bool Create( LPCTSTR lpApplicationName, LPTSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCTSTR lpCurrentDirectory, LPSTARTUPINFO lpStartupInfo )
	{
		PROCESS_INFORMATION process_info;
		if( !CreateProcess( lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, &process_info ) )
			return false;
		cSubProcess *sub_process;
		try
		{
			sub_process = new cSubProcess( process_info );
		}
		catch( ... )
		{
			return false;
		}
		SwitchToSubObject( sub_process );
		return true;
	}
	DWORD ResumeThread()
	{
		if( GetSubObject() == NULL )
			return ( DWORD )-1;
		return ::ResumeThread( GetSubObject()->ThreadHandle() );
	}
	HANDLE ProcessHandle() const 
	{
		if( GetSubObject() == NULL )
			return INVALID_HANDLE_VALUE;
		return GetSubObject()->ProcessHandle();
	}
	HANDLE ThreadHandle() const 
	{
		if( GetSubObject() == NULL )
			return INVALID_HANDLE_VALUE;
		return GetSubObject()->ThreadHandle();
	}
	BOOL ExitCode( LPDWORD lpExitCode )
	{
		if( GetSubObject() == NULL )
			return FALSE;
		return ::GetExitCodeProcess( GetSubObject()->ProcessHandle(), lpExitCode );
	}
	BOOL TerminateProcess( UINT uExitCode )
	{
		if( GetSubObject() == NULL )
			return FALSE;
		return ::TerminateProcess( GetSubObject()->ProcessHandle(), uExitCode );
	}
};

#endif
